#ifndef  __LITE_QUEUE_H__
#define  __LITE_QUEUE_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include "Lite_Queue_Config.h"

typedef enum
{
    QUEUE_SEND_TO_BACK = 0,   /* After the queue is full, if more data is added to the queue, it will return to the initial position and start joining the queue. */
    QUEUE_DISCARD,            /* After the queue is full, if more data is added to the queue, the current data will be discarded. */
    
}QueueWriteMode;

typedef enum
{
    LITE_QUEUE_LOCK = 0,
    LITE_QUEUE_UNLOCK,

    LITE_QUEUE_IDLE,
    LITE_QUEUE_WRITE_BUSY,
    LITE_QUEUE_READ_BUSY,
    LITE_QUEUE_ERR,
    LITE_QUEUE_OK,

    LITE_QUEUE_EMPTY,
    LITE_QUEUE_NONEMPTY,

    LITE_QUEUE_FULL,
    LITE_QUEUE_NONEFULL,

}LiteQueue_Status;

typedef void (*LiteQueue_Callback_t)(LiteQueue_Status status);

/*
                 *tail: Move this pointer when writing data
                   ↓
                     item_num_1     item_num_2                 item_num_x
 ---------------    -----------    -----------                -----------
|   LiteQueue   |  | item_size |  | item_size |    ......    | item_size |
 ---------------    -----------    -----------                -----------  
                   ↑
                 *head: Move the pointer when reading data

LiteQueue : Structure describing queue parameters.
item_num_x: Number of items.
item_size : The size of each list item set when creating the queue, unit: bytes, used to store data received in the queue.
*/
typedef struct 
{
    volatile uint8_t  queue_write_lock;     /* write queue lock */
    volatile uint8_t  queue_read_lock;      /* read queue lock */   

    uint8_t   *head;                        /* Point to the head of the queue, du from the head of the queue */
    uint8_t   *tail;                        /* Point to the end of the queue and write data from the end of the queue */

    size_t    item_num;                     /* The number of list items in the queue */
    size_t    item_size;                    /* How much address space each list item occupies, unit: bytes */

    size_t    unread_item;                  /* The number of unread list items remaining in the queue */

    LiteQueue_Callback_t LiteQueue_Callback;

}LiteQueue, *pLiteQueue;

#define  LITE_QUEUE_WRITE_LOCK(__QUEUE__)      do{                                                              \
                                                    if((__QUEUE__)->queue_write_lock == LITE_QUEUE_LOCK)        \
                                                    {                                                           \
                                                        (__QUEUE__)->LiteQueue_Callback(LITE_QUEUE_WRITE_BUSY); \
                                                        return LITE_QUEUE_WRITE_BUSY;                           \
                                                    }                                                           \
                                                    else                                                        \
                                                    {                                                           \
                                                        (__QUEUE__)->queue_write_lock = LITE_QUEUE_LOCK;        \
                                                    }                                                           \
                                                 }while(0)

#define  LITE_QUEUE_WRITE_UNLOCK(__QUEUE__)    do{                                                              \
                                                    (__QUEUE__)->queue_write_lock = LITE_QUEUE_UNLOCK;          \
                                                 }while(0)

#define  LITE_QUEUE_READ_LOCK(__QUEUE__)       do{                                                              \
                                                    if((__QUEUE__)->queue_read_lock == LITE_QUEUE_LOCK)         \
                                                    {                                                           \
                                                        (__QUEUE__)->LiteQueue_Callback(LITE_QUEUE_READ_BUSY);  \
                                                        return LITE_QUEUE_READ_BUSY;                            \
                                                    }                                                           \
                                                    else                                                        \
                                                    {                                                           \
                                                        (__QUEUE__)->queue_read_lock = LITE_QUEUE_LOCK;         \
                                                    }                                                           \
                                                 }while(0)

#define  LITE_QUEUE_READ_UNLOCK(__QUEUE__)     do{                                                              \
                                                    (__QUEUE__)->queue_read_lock = LITE_QUEUE_UNLOCK;           \
                                                 }while(0)


extern LiteQueue *xLiteQueue_Create(size_t item_num, size_t item_size, LiteQueue_Callback_t callback);
extern LiteQueue_Status xWrite_To_LiteQueue(LiteQueue *queue, uint8_t *buff, QueueWriteMode WriteMode);  
extern LiteQueue_Status Read_From_LiteQueue(LiteQueue *queue, uint8_t *buff);                                            
extern LiteQueue_Status isLiteQueue_Empty(LiteQueue *queue);
extern LiteQueue_Status isLiteQueue_Full(LiteQueue *queue);
extern LiteQueue_Status LiteQueue_Clear(LiteQueue *queue);
extern LiteQueue_Status LiteQueue_Delete(LiteQueue *queue);


#if(QUEUE_ERROR_CALLBACK == QUEUE_ENABLE)
#define  LiteQueue_Create(item_num, item_size, callback)    xLiteQueue_Create(item_num, item_size, callback)
#else
#define  LiteQueue_Create(item_num, item_size)              xLiteQueue_Create((item_num), (item_size), NULL)
#endif 


#define  Write_To_Back_LiteQueue(queue, buff)               xWrite_To_LiteQueue((queue), (buff), (QUEUE_SEND_TO_BACK))
#define  Write_Discard_LiteQueue(queue, buff)               xWrite_To_LiteQueue((queue), (buff), (QUEUE_DISCARD))


#endif   /* __LITE_QUEUE_H__ */

